home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / ftp / glob.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-12  |  10.1 KB  |  666 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #ifndef lint
  19. static char sccsid[] = "@(#)glob.c    5.7 (Berkeley) 12/14/88";
  20. #endif /* not lint */
  21.  
  22. /*
  23.  * C-shell glob for random programs.
  24.  */
  25.  
  26. #include <sys/param.h>
  27. #include <sys/stat.h>
  28. #include <sys/dir.h>
  29.  
  30. #include <stdio.h>
  31. #include <errno.h>
  32. #include <pwd.h>
  33.  
  34. #define    QUOTE 0200
  35. #define    TRIM 0177
  36. #define    eq(a,b)        (strcmp(a, b)==0)
  37. #define    GAVSIZ        (NCARGS/6)
  38. #define    isdir(d)    ((d.st_mode & S_IFMT) == S_IFDIR)
  39.  
  40. static    char **gargv;        /* Pointer to the (stack) arglist */
  41. static    int gargc;        /* Number args in gargv */
  42. static    int gnleft;
  43. static    short gflag;
  44. static    int tglob();
  45. char    **glob();
  46. char    *globerr;
  47. char    *home;
  48. struct    passwd *getpwnam();
  49. extern    int errno;
  50. static    char *strspl(), *strend();
  51. char    *malloc(), *strcpy(), *strcat();
  52. char    **copyblk();
  53.  
  54. static    int globcnt;
  55.  
  56. char    *globchars = "`{[*?";
  57.  
  58. static    char *gpath, *gpathp, *lastgpathp;
  59. static    int globbed;
  60. static    char *entp;
  61. static    char **sortbas;
  62.  
  63. char **
  64. glob(v)
  65.     register char *v;
  66. {
  67.     char agpath[BUFSIZ];
  68.     char *agargv[GAVSIZ];
  69.     char *vv[2];
  70.     vv[0] = v;
  71.     vv[1] = 0;
  72.     gflag = 0;
  73.     rscan(vv, tglob);
  74.     if (gflag == 0)
  75.         return (copyblk(vv));
  76.  
  77.     globerr = 0;
  78.     gpath = agpath; gpathp = gpath; *gpathp = 0;
  79.     lastgpathp = &gpath[sizeof agpath - 2];
  80.     ginit(agargv); globcnt = 0;
  81.     collect(v);
  82.     if (globcnt == 0 && (gflag&1)) {
  83.         blkfree(gargv), gargv = 0;
  84.         return (0);
  85.     } else
  86.         return (gargv = copyblk(gargv));
  87. }
  88.  
  89. static
  90. ginit(agargv)
  91.     char **agargv;
  92. {
  93.  
  94.     agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
  95.     gnleft = NCARGS - 4;
  96. }
  97.  
  98. static
  99. collect(as)
  100.     register char *as;
  101. {
  102.     if (eq(as, "{") || eq(as, "{}")) {
  103.         Gcat(as, "");
  104.         sort();
  105.     } else
  106.         acollect(as);
  107. }
  108.  
  109. static
  110. acollect(as)
  111.     register char *as;
  112. {
  113.     register int ogargc = gargc;
  114.  
  115.     gpathp = gpath; *gpathp = 0; globbed = 0;
  116.     expand(as);
  117.     if (gargc != ogargc)
  118.         sort();
  119. }
  120.  
  121. static
  122. sort()
  123. {
  124.     register char **p1, **p2, *c;
  125.     char **Gvp = &gargv[gargc];
  126.  
  127.     p1 = sortbas;
  128.     while (p1 < Gvp-1) {
  129.         p2 = p1;
  130.         while (++p2 < Gvp)
  131.             if (strcmp(*p1, *p2) > 0)
  132.                 c = *p1, *p1 = *p2, *p2 = c;
  133.         p1++;
  134.     }
  135.     sortbas = Gvp;
  136. }
  137.  
  138. static
  139. expand(as)
  140.     char *as;
  141. {
  142.     register char *cs;
  143.     register char *sgpathp, *oldcs;
  144.     struct stat stb;
  145.  
  146.     sgpathp = gpathp;
  147.     cs = as;
  148.     if (*cs == '~' && gpathp == gpath) {
  149.         addpath('~');
  150.         for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
  151.             addpath(*cs++);
  152.         if (!*cs || *cs == '/') {
  153.             if (gpathp != gpath + 1) {
  154.                 *gpathp = 0;
  155.                 if (gethdir(gpath + 1))
  156.                     globerr = "Unknown user name after ~";
  157.                 (void) strcpy(gpath, gpath + 1);
  158.             } else
  159.                 (void) strcpy(gpath, home);
  160.             gpathp = strend(gpath);
  161.         }
  162.     }
  163.     while (!any(*cs, globchars)) {
  164.         if (*cs == 0) {
  165.             if (!globbed)
  166.                 Gcat(gpath, "");
  167.             else if (stat(gpath, &stb) >= 0) {
  168.                 Gcat(gpath, "");
  169.                 globcnt++;
  170.             }
  171.             goto endit;
  172.         }
  173.         addpath(*cs++);
  174.     }
  175.     oldcs = cs;
  176.     while (cs > as && *cs != '/')
  177.         cs--, gpathp--;
  178.     if (*cs == '/')
  179.         cs++, gpathp++;
  180.     *gpathp = 0;
  181.     if (*oldcs == '{') {
  182.         (void) execbrc(cs, ((char *)0));
  183.         return;
  184.     }
  185.     matchdir(cs);
  186. endit:
  187.     gpathp = sgpathp;
  188.     *gpathp = 0;
  189. }
  190.  
  191. static
  192. matchdir(pattern)
  193.     char *pattern;
  194. {
  195.     struct stat stb;
  196.     register struct direct *dp;
  197.     DIR *dirp;
  198.  
  199.     dirp = opendir(gpath);
  200.     if (dirp == NULL) {
  201.         if (globbed)
  202.             return;
  203.         goto patherr2;
  204.     }
  205.     if (fstat(dirp->dd_fd, &stb) < 0)
  206.         goto patherr1;
  207.     if (!isdir(stb)) {
  208.         errno = ENOTDIR;
  209.         goto patherr1;
  210.     }
  211.     while ((dp = readdir(dirp)) != NULL) {
  212.         if (dp->d_ino == 0)
  213.             continue;
  214.         if (match(dp->d_name, pattern)) {
  215.             Gcat(gpath, dp->d_name);
  216.             globcnt++;
  217.         }
  218.     }
  219.     closedir(dirp);
  220.     return;
  221.  
  222. patherr1:
  223.     closedir(dirp);
  224. patherr2:
  225.     globerr = "Bad directory components";
  226. }
  227.  
  228. static
  229. execbrc(p, s)
  230.     char *p, *s;
  231. {
  232.     char restbuf[BUFSIZ + 2];
  233.     register char *pe, *pm, *pl;
  234.     int brclev = 0;
  235.     char *lm, savec, *sgpathp;
  236.  
  237.     for (lm = restbuf; *p != '{'; *lm++ = *p++)
  238.         continue;
  239.     for (pe = ++p; *pe; pe++)
  240.     switch (*pe) {
  241.  
  242.     case '{':
  243.         brclev++;
  244.         continue;
  245.  
  246.     case '}':
  247.         if (brclev == 0)
  248.             goto pend;
  249.         brclev--;
  250.         continue;
  251.  
  252.     case '[':
  253.         for (pe++; *pe && *pe != ']'; pe++)
  254.             continue;
  255.         continue;
  256.     }
  257. pend:
  258.     brclev = 0;
  259.     for (pl = pm = p; pm <= pe; pm++)
  260.     switch (*pm & (QUOTE|TRIM)) {
  261.  
  262.     case '{':
  263.         brclev++;
  264.         continue;
  265.  
  266.     case '}':
  267.         if (brclev) {
  268.             brclev--;
  269.             continue;
  270.         }
  271.         goto doit;
  272.  
  273.     case ','|QUOTE:
  274.     case ',':
  275.         if (brclev)
  276.             continue;
  277. doit:
  278.         savec = *pm;
  279.         *pm = 0;
  280.         (void) strcpy(lm, pl);
  281.         (void) strcat(restbuf, pe + 1);
  282.         *pm = savec;
  283.         if (s == 0) {
  284.             sgpathp = gpathp;
  285.             expand(restbuf);
  286.             gpathp = sgpathp;
  287.             *gpathp = 0;
  288.         } else if (amatch(s, restbuf))
  289.             return (1);
  290.         sort();
  291.         pl = pm + 1;
  292.         if (brclev)
  293.             return (0);
  294.         continue;
  295.  
  296.     case '[':
  297.         for (pm++; *pm && *pm != ']'; pm++)
  298.             continue;
  299.         if (!*pm)
  300.             pm--;
  301.         continue;
  302.     }
  303.     if (brclev)
  304.         goto doit;
  305.     return (0);
  306. }
  307.  
  308. static
  309. match(s, p)
  310.     char *s, *p;
  311. {
  312.     register int c;
  313.     register char *sentp;
  314.     char sglobbed = globbed;
  315.  
  316.     if (*s == '.' && *p != '.')
  317.         return (0);
  318.     sentp = entp;
  319.     entp = s;
  320.     c = amatch(s, p);
  321.     entp = sentp;
  322.     globbed = sglobbed;
  323.     return (c);
  324. }
  325.  
  326. static
  327. amatch(s, p)
  328.     register char *s, *p;
  329. {
  330.     register int scc;
  331.     int ok, lc;
  332.     char *sgpathp;
  333.     struct stat stb;
  334.     int c, cc;
  335.  
  336.     globbed = 1;
  337.     for (;;) {
  338.         scc = *s++ & TRIM;
  339.         switch (c = *p++) {
  340.  
  341.         case '{':
  342.             return (execbrc(p - 1, s - 1));
  343.  
  344.         case '[':
  345.             ok = 0;
  346.             lc = 077777;
  347.             while (cc = *p++) {
  348.                 if (cc == ']') {
  349.                     if (ok)
  350.                         break;
  351.                     return (0);
  352.                 }
  353.                 if (cc == '-') {
  354.                     if (lc <= scc && scc <= *p++)
  355.                         ok++;
  356.                 } else
  357.                     if (scc == (lc = cc))
  358.                         ok++;
  359.             }
  360.             if (cc == 0)
  361.                 if (ok)
  362.                     p--;
  363.                 else
  364.                     return 0;
  365.             continue;
  366.  
  367.         case '*':
  368.             if (!*p)
  369.                 return (1);
  370.             if (*p == '/') {
  371.                 p++;
  372.                 goto slash;
  373.             }
  374.             s--;
  375.             do {
  376.                 if (amatch(s, p))
  377.                     return (1);
  378.             } while (*s++);
  379.             return (0);
  380.  
  381.         case 0:
  382.             return (scc == 0);
  383.  
  384.         default:
  385.             if (c != scc)
  386.                 return (0);
  387.             continue;
  388.  
  389.         case '?':
  390.             if (scc == 0)
  391.                 return (0);
  392.             continue;
  393.  
  394.         case '/':
  395.             if (scc)
  396.                 return (0);
  397. slash:
  398.             s = entp;
  399.             sgpathp = gpathp;
  400.             while (*s)
  401.                 addpath(*s++);
  402.             addpath('/');
  403.             if (stat(gpath, &stb) == 0 && isdir(stb))
  404.                 if (*p == 0) {
  405.                     Gcat(gpath, "");
  406.                     globcnt++;
  407.                 } else
  408.                     expand(p);
  409.             gpathp = sgpathp;
  410.             *gpathp = 0;
  411.             return (0);
  412.         }
  413.     }
  414. }
  415.  
  416. static
  417. Gmatch(s, p)
  418.     register char *s, *p;
  419. {
  420.     register int scc;
  421.     int ok, lc;
  422.     int c, cc;
  423.  
  424.     for (;;) {
  425.         scc = *s++ & TRIM;
  426.         switch (c = *p++) {
  427.  
  428.         case '[':
  429.             ok = 0;
  430.             lc = 077777;
  431.             while (cc = *p++) {
  432.                 if (cc == ']') {
  433.                     if (ok)
  434.                         break;
  435.                     return (0);
  436.                 }
  437.                 if (cc == '-') {
  438.                     if (lc <= scc && scc <= *p++)
  439.                         ok++;
  440.                 } else
  441.                     if (scc == (lc = cc))
  442.                         ok++;
  443.             }
  444.             if (cc == 0)
  445.                 if (ok)
  446.                     p--;
  447.                 else
  448.                     return 0;
  449.             continue;
  450.  
  451.         case '*':
  452.             if (!*p)
  453.                 return (1);
  454.             for (s--; *s; s++)
  455.                 if (Gmatch(s, p))
  456.                     return (1);
  457.             return (0);
  458.  
  459.         case 0:
  460.             return (scc == 0);
  461.  
  462.         default:
  463.             if ((c & TRIM) != scc)
  464.                 return (0);
  465.             continue;
  466.  
  467.         case '?':
  468.             if (scc == 0)
  469.                 return (0);
  470.             continue;
  471.  
  472.         }
  473.     }
  474. }
  475.  
  476. static
  477. Gcat(s1, s2)
  478.     register char *s1, *s2;
  479. {
  480.     register int len = strlen(s1) + strlen(s2) + 1;
  481.  
  482.     if (len >= gnleft || gargc >= GAVSIZ - 1)
  483.         globerr = "Arguments too long";
  484.     else {
  485.         gargc++;
  486.         gnleft -= len;
  487.         gargv[gargc] = 0;
  488.         gargv[gargc - 1] = strspl(s1, s2);
  489.     }
  490. }
  491.  
  492. static
  493. addpath(c)
  494.     char c;
  495. {
  496.  
  497.     if (gpathp >= lastgpathp)
  498.         globerr = "Pathname too long";
  499.     else {
  500.         *gpathp++ = c;
  501.         *gpathp = 0;
  502.     }
  503. }
  504.  
  505. static
  506. rscan(t, f)
  507.     register char **t;
  508.     int (*f)();
  509. {
  510.     register char *p, c;
  511.  
  512.     while (p = *t++) {
  513.         if (f == tglob)
  514.             if (*p == '~')
  515.                 gflag |= 2;
  516.             else if (eq(p, "{") || eq(p, "{}"))
  517.                 continue;
  518.         while (c = *p++)
  519.             (*f)(c);
  520.     }
  521. }
  522. /*
  523. static
  524. scan(t, f)
  525.     register char **t;
  526.     int (*f)();
  527. {
  528.     register char *p, c;
  529.  
  530.     while (p = *t++)
  531.         while (c = *p)
  532.             *p++ = (*f)(c);
  533. } */
  534.  
  535. static
  536. tglob(c)
  537.     register char c;
  538. {
  539.  
  540.     if (any(c, globchars))
  541.         gflag |= c == '{' ? 2 : 1;
  542.     return (c);
  543. }
  544. /*
  545. static
  546. trim(c)
  547.     char c;
  548. {
  549.  
  550.     return (c & TRIM);
  551. } */
  552.  
  553.  
  554. letter(c)
  555.     register char c;
  556. {
  557.  
  558.     return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_');
  559. }
  560.  
  561. digit(c)
  562.     register char c;
  563. {
  564.  
  565.     return (c >= '0' && c <= '9');
  566. }
  567.  
  568. any(c, s)
  569.     register int c;
  570.     register char *s;
  571. {
  572.  
  573.     while (*s)
  574.         if (*s++ == c)
  575.             return(1);
  576.     return(0);
  577. }
  578. blklen(av)
  579.     register char **av;
  580. {
  581.     register int i = 0;
  582.  
  583.     while (*av++)
  584.         i++;
  585.     return (i);
  586. }
  587.  
  588. char **
  589. blkcpy(oav, bv)
  590.     char **oav;
  591.     register char **bv;
  592. {
  593.     register char **av = oav;
  594.  
  595.     while (*bv != 0) {
  596.         *av = (char *)malloc(strlen(*bv)+1);
  597.         strcpy(*av,*bv);
  598.         av++;
  599.         bv++;
  600.     }
  601.     *av = 0;
  602.     return (oav);
  603. }
  604.  
  605. blkfree(av0)
  606.     char **av0;
  607. {
  608.     register char **av = av0;
  609.  
  610.     while (*av)
  611.         free(*av++);
  612. }
  613.  
  614. static
  615. char *
  616. strspl(cp, dp)
  617.     register char *cp, *dp;
  618. {
  619.     register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1));
  620.  
  621.     if (ep == (char *)0)
  622.         fatal("Out of memory");
  623.     (void) strcpy(ep, cp);
  624.     (void) strcat(ep, dp);
  625.     return (ep);
  626. }
  627.  
  628. char **
  629. copyblk(v)
  630.     register char **v;
  631. {
  632.     register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) *
  633.                         sizeof(char **)));
  634.     if (nv == (char **)0)
  635.         fatal("Out of memory");
  636.  
  637.     return (blkcpy(nv, v));
  638. }
  639.  
  640. static
  641. char *
  642. strend(cp)
  643.     register char *cp;
  644. {
  645.  
  646.     while (*cp)
  647.         cp++;
  648.     return (cp);
  649. }
  650. /*
  651.  * Extract a home directory from the password file
  652.  * The argument points to a buffer where the name of the
  653.  * user whose home directory is sought is currently.
  654.  * We write the home directory of the user back there.
  655.  */
  656. gethdir(home)
  657.     char *home;
  658. {
  659.     register struct passwd *pp = getpwnam(home);
  660.  
  661.     if (!pp || home + strlen(pp->pw_dir) >= lastgpathp)
  662.         return (1);
  663.     (void) strcpy(home, pp->pw_dir);
  664.     return (0);
  665. }
  666.